package home

import (
	"adai.design/homeserver/devices"
	"adai.design/homeserver/members"
	"adai.design/homeserver/log"
	"encoding/json"
	"adai.design/homeserver/home/data"
	"fmt"
	"adai.design/homeserver/db"
	"time"
)

type Home struct {
	hub 		*Hub

	Id 			string		`json:"id" bson:"id"`
	Name 		string		`json:"name" bson:"name"`

	Members 	[]*Member	`json:"members" bson:"members"`
	Rooms 		[]*Room		`json:"rooms" bson:"rooms"`

	Services 	[]*Service		`json:"services,omitempty" bson:"services,omitempty"`
	Scenes 		[]*Scene		`json:"scenes,omitempty" bson:"scenes,omitempty"`
	Containers 	[]*Container 	`json:"containers,omitempty" bson:"containers,omitempty"`
	Triggers 	[]*Trigger		`json:"triggers,omitempty" bson:"triggers,omitempty"`

	memberManager 		*MemberManager
	roomManager 		*RoomManager
	sceneManager 		*SceneManager
	serviceManager   	*ServiceManager
	containerManager 	*ContainerManager
	triggerManager 		*TriggerManager

	devPkg 	chan *devices.MessagePkg
	memberPkg chan *members.MessagePkg

	router		map[string]apiInterface
}

func (h *Home) getRoomNameById(id string) string {
	for _, r := range h.Rooms {
		if r.Id == id {
			return r.Name
		}
	}
	return "默认房间"
}

// 将消息发送给设备
func (h *Home) postMessageToContainer(id string, msg *devices.Message) error {
	//log.Debug("post to container(%s) message(%s)", id, msg.String())
	pkg := &devices.MessagePkg{
		DevId: id,
		HomeId: h.Id,
		Msg: msg,
	}
	h.hub.devSend <- pkg
	return nil
}

func (h *Home) putMessageToMember(msg *members.Message) error {
	//buf, _ := json.Marshal(msg)
	//log.Info("put message(%s)", string(buf))
	for _, member := range h.Members {
		pkg := &members.MessagePkg{
			Type: members.PkgTypeContext,
			Ctx: &members.Context{
				HomeId: h.Id,
				MemberId: member.Id,
			},
			Msg: msg,
		}
		msg.Home = h.Id
		h.hub.memberSend <- pkg
	}
	return nil
}

// 推送消息给用户 (主要推过Apple APNS推送消息给用户)
func (h *Home) pushNotifyToMember(notify *members.APNSAlert) error {
	log.Info("push to alert(%s)", notify.String())
	for _, m := range h.Members {
		members.PushNotificationToMember(m.Id, notify)
	}
	db.HomePushMark(&db.HomePushInfo{
		HomeId: h.Id,
		Body: notify.String(),
		Time: time.Now(),
	})
	return nil
}

//刷新Characteristic状态
func (h *Home) refreshCharacteristic(id string, chars ...*data.Characteristic) error {
	// 1)通知用户
	cchars := &data.ContainerCharacteristic{
		Id: id,
		IsReachable: true,
		Chars: chars,
	}

	buf, _ := json.Marshal(cchars)
	put := &members.Message{
		Path: PathContainerCharacteristic,
		Method: members.MsgMethodPut,
		Data: buf,
	}
	h.putMessageToMember(put)

	// 2)检查是否需要推送
	for _, char := range chars {
		h.serviceManager.CheckNotify(h, char)
	}

	// 3)检查是否触发自动化
	for _, chars := range chars {
		h.triggerManager.checkCharacteristicTrigger(h, chars)
	}
	return nil
}

func (h *Home) handleContainerPkg(id string, msg *devices.Message) error {
	h.containerManager.handlePackage(h, id, msg)
	return nil
}

func (h *Home) receiveContainerPkg(pkg *devices.MessagePkg) {
	log.Debug("%s", pkg.Msg.String())
	if h.devPkg != nil {
		h.devPkg <- pkg
	}
}

func (h *Home) receiveMemberPkg(pkg *members.MessagePkg) {
	log.Debug("%s", pkg.String())
	if h.memberPkg != nil {
		h.memberPkg <- pkg
	}
}

func (h *Home) handleMemberPkg(pkg *members.MessagePkg) error {
	if v, ok := h.router[pkg.Msg.Path]; ok {
		return v.Handle(h, pkg)
	}
	return fmt.Errorf("member message path(%s) 404 not found", pkg.Msg.Path)
}

func (h *Home) replyMemberResult(pkg *members.MessagePkg) error {
	if pkg.Type == members.PkgTypeContext {
		members.SendPackage(pkg)
	} else {
		defer func(){
			if err := recover(); err != nil {
				log.Error("ack member result err: %s", err)
			}
		}()
		pkg.Ctx.Result <- pkg
	}
	return nil
}

func (h *Home) Handle(home *Home, pkg *members.MessagePkg) error {
	msg := pkg.Msg
	if msg.Method == members.MsgMethodGet {
		buf, _ := json.Marshal(h)
		ack := &members.MessagePkg{
			Type: pkg.Type,
			Ctx: pkg.Ctx,
			Msg: &members.Message{
				Path: pkg.Msg.Path,
				Method: pkg.Msg.Method,
				State: "ok",
				Home: h.Id,
				Data: buf,
			},
		}
		h.replyMemberResult(ack)
	}
	return nil
}

func (h *Home) run(hub *Hub) {
	h.hub = hub
	h.devPkg = make(chan *devices.MessagePkg, 5)
	h.memberPkg = make(chan *members.MessagePkg, 5)

	h.router = make(map[string]apiInterface)
	h.router[PathHome] = h

	h.roomManager = &RoomManager{rooms: h.Rooms}
	h.router[PathRoom] = h.roomManager

	h.containerManager = &ContainerManager{containers: h.Containers}
	h.router[PathContainer] = h.containerManager
	h.router[PathContainerCharacteristic] = h.containerManager
	h.router[PathCharacteristic] = h.containerManager

	h.serviceManager = &ServiceManager{services: h.Services}
	h.router[PathService] = h.serviceManager

	h.memberManager = &MemberManager{h.Members}
	h.router[PathMember] = h.memberManager

	h.sceneManager = &SceneManager{scenes: h.Scenes}
	h.router[PathScene] = h.sceneManager

	h.triggerManager = &TriggerManager{triggers: h.Triggers}
	h.router[PathAutomation] = h.triggerManager
	h.router[PathLocation] = h.triggerManager

	statistic := &statistics{}
	h.router[PathStatisticCharacteristic] = statistic
	h.router[PathStatisticLocation] = statistic
	h.router[PathStatisticPush] = statistic

	h.triggerManager.run()

	for {
		select {
		case pkg, ok := <-h.devPkg:
			if ok {
				h.handleContainerPkg(pkg.DevId, pkg.Msg)
			}

		case ticker, ok := <-h.triggerManager.ticker:
			if ok {
				h.triggerManager.checkTimerTrigger(h, ticker)
			}

		case pkg, ok := <-h.memberPkg:
			if ok {
				h.handleMemberPkg(pkg)
			}

		}
	}
}